package zappa.com.controller;

import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.log4j.Logger;
import org.jmesa.limit.Limit;
import org.jmesa.model.PageItems;
import org.jmesa.model.TableModelUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import zappa.com.bean.ZapatoId;
import zappa.com.bean.ZapatoModify;
import zappa.com.bean.ZapatoSearch;
import zappa.com.domain.Zapato;
import zappa.com.service.IZapatoService;
import zappa.com.validator.ZapatoValidator;
import zappa.com.validator.ZapatoModifyValidator;
import zappa.com.validator.ZapatoSearchValidator;

@Controller
public class ZapatoController {

	private static final Logger LOG = Logger.getLogger(ZapatoController.class);
	private static final String TABLE_MODEL="tableModel";
	private static final String GRID_LIST_TOKEN="gridListToken";
	//views
	private static final String SEARCH_VIEW="zapato/searchZapato";
	private static final String CREATE_VIEW="zapato/createZapato";
	private static final String CREATE_OK_VIEW="zapato/createZapatoOk";
	private static final String LIST_VIEW="zapato/listZapato";
	private static final String DETAIL_VIEW="zapato/detailZapato";
	private static final String MODIFY_VIEW="zapato/modifyZapato";
	private static final String MODIFY_OK_VIEW="zapato/modifyZapatoOk";
	private static final String DELETE_VIEW="zapato/deleteZapato";
	private static final String DELETE_OK_VIEW="zapato/deleteZapatoOk";
	private static final String ERROR_VIEW="error";
	//commands
	private static final String SEARCH_COMMAND="zapatoSearch";
	private static final String LIST_COMMAND="zapatoList";
	private static final String OBJECT_COMMAND="zapato";

	//services
	@Autowired
	private IZapatoService zapatoService;

	@InitBinder
	protected void initBinder(WebDataBinder binder) throws Exception {
		if(binder.getTarget() instanceof ZapatoSearch){
			binder.setValidator(new ZapatoSearchValidator());
		}else{
			if(binder.getTarget() instanceof ZapatoModify){
				binder.setValidator(new ZapatoModifyValidator());
			}else{
				if(binder.getTarget() instanceof Zapato){
					binder.setValidator(new ZapatoValidator());
				}
			}
		}
	}

	@ExceptionHandler(Exception.class)
	public ModelAndView handleException(Exception e, HttpServletRequest request) {
		LOG.error(e.getMessage(), e);
		return new ModelAndView(ERROR_VIEW);
	}

	@RequestMapping("/zapato/search")
	public ModelAndView search() {
		ZapatoSearch zapatoSearch=new ZapatoSearch();
		ModelAndView mv=new ModelAndView(SEARCH_VIEW);
		mv.addObject(SEARCH_COMMAND, zapatoSearch);
		return mv;
	}
	@RequestMapping("/zapato/create")
	public ModelAndView create() {
		Zapato zapato=new Zapato();
		ModelAndView mv=new ModelAndView(CREATE_VIEW);
		mv.addObject(OBJECT_COMMAND, zapato);
		return mv;
	}
	@RequestMapping("/zapato/processCreate")
	public ModelAndView processCreate(HttpServletRequest request, @ModelAttribute("zapato") @Valid Zapato zapato, 
			BindingResult result) throws Exception{
		if(result.hasErrors()){
			return create();
		}
		zapatoService.create(zapato);
		ModelAndView mv=new ModelAndView(CREATE_OK_VIEW);
		return mv;
	}
	@RequestMapping("/zapato/list")
	public ModelAndView list(HttpServletRequest request, @ModelAttribute("zapatoSearch") @Valid ZapatoSearch zapatoSearch, 
			BindingResult result) throws Exception{
		if(result.hasErrors()){
			ModelAndView mv=new ModelAndView(SEARCH_VIEW);
			mv.addObject(SEARCH_COMMAND, zapatoSearch);
			return mv;
		}
		/**
		 * TODO: In case of a service with pagination support call the service in the getGridItems implementations
		 * and avoid the use of the session
		 */
		List<Zapato> zapatoList=zapatoService.search(zapatoSearch);
		request.getSession().setAttribute(GRID_LIST_TOKEN, zapatoList);
		Collection<Zapato> gridItems=getGridItems(request);
		ModelAndView mv=new ModelAndView(LIST_VIEW);
		mv.addObject(SEARCH_COMMAND, zapatoSearch);
		mv.addObject(LIST_COMMAND, gridItems);
		return mv;
	}
	@RequestMapping("/zapato/paginate")
	public ModelAndView paginate(HttpServletRequest request) {	
		if(request.getSession().getAttribute(GRID_LIST_TOKEN)==null){
			return search();
		}
		Collection<Zapato> gridItems=getGridItems(request);
		ModelAndView mv=new ModelAndView(LIST_VIEW);
		mv.addObject(LIST_COMMAND, gridItems);
		return mv;
	}
	@SuppressWarnings("unchecked")
	private Collection<Zapato> getGridItems(final HttpServletRequest request){
		return (Collection<Zapato>)TableModelUtils.getItems(TABLE_MODEL, request, new PageItems() {
			public int getTotalRows(Limit limit) {
				//TODO: reimplement in case of a service with pagination support
				List<Zapato> zapatoList=(List<Zapato>) request.getSession().getAttribute(GRID_LIST_TOKEN);
				return zapatoList.size();
			}
			public Collection<Zapato> getItems(Limit limit) {
				int rowStart = limit.getRowSelect().getRowStart();
				int rowEnd = limit.getRowSelect().getRowEnd();
				//TODO: reimplement in case of a service with pagination support
				List<Zapato> zapatoList=(List<Zapato>) request.getSession().getAttribute(GRID_LIST_TOKEN);
				return zapatoList.subList(rowStart, rowEnd);
			}
		});
	}
	@RequestMapping("/zapato/detail")
	public ModelAndView detail(HttpServletRequest request, @ModelAttribute("zapatoId") ZapatoId zapatoId, 
			BindingResult result) throws Exception{
		if(result.hasErrors()){
			return search();
		}
		Zapato zapato=zapatoService.find(zapatoId);
		ModelAndView mv=new ModelAndView(DETAIL_VIEW);
		mv.addObject(OBJECT_COMMAND, zapato);
		return mv;
	}
	@RequestMapping("/zapato/modify")
	public ModelAndView modify(HttpServletRequest request, @ModelAttribute("zapatoId") ZapatoId zapatoId, 
			BindingResult result) throws Exception{
		if(result.hasErrors()){
			return search();
		}
		Zapato zapato=zapatoService.find(zapatoId);
		ModelAndView mv=new ModelAndView(MODIFY_VIEW);
		mv.addObject(OBJECT_COMMAND, zapato);
		return mv;
	}
	@RequestMapping("/zapato/processModify")
	public ModelAndView processModify(HttpServletRequest request, @ModelAttribute("zapato") @Valid ZapatoModify zapatoModify, 
			BindingResult result) throws Exception{
		ZapatoId zapatoId=new ZapatoId();
		zapatoId.setId(zapatoModify.getId());
		Zapato zapato=zapatoService.find(zapatoId);
		if(result.hasErrors()){
			ModelAndView mv=new ModelAndView(MODIFY_VIEW);
			mv.addObject(OBJECT_COMMAND, zapato);
			return mv;
		}
		zapato.setId(zapatoModify.getId());
		zapato.setTalle(zapatoModify.getTalle());
		zapato.setColor(zapatoModify.getColor());
		zapato.setMarca(zapatoModify.getMarca());		

		zapatoService.update(zapato);
		ModelAndView mv=new ModelAndView(MODIFY_OK_VIEW);
		return mv;
	}
	@RequestMapping("/zapato/delete")
	public ModelAndView delete(HttpServletRequest request, @ModelAttribute("zapatoId") ZapatoId zapatoId, 
			BindingResult result) throws Exception{
		if(result.hasErrors()){
			return search();
		}
		Zapato zapato=zapatoService.find(zapatoId);
		ModelAndView mv=new ModelAndView(DELETE_VIEW);
		mv.addObject(OBJECT_COMMAND, zapato);
		return mv;
	}
	@RequestMapping("/zapato/processDelete")
	public ModelAndView processDelete(HttpServletRequest request, @ModelAttribute("zapatoId") ZapatoId zapatoId, 
			BindingResult result) throws Exception{
		if(result.hasErrors()){
			ModelAndView mv=new ModelAndView(DELETE_VIEW);
			Zapato zapato=zapatoService.find(zapatoId);
			mv.addObject(OBJECT_COMMAND, zapato);
			return mv;
		}
		zapatoService.delete(zapatoId);
		ModelAndView mv=new ModelAndView(DELETE_OK_VIEW);
		return mv;
	}
}
